'use strict';

const Controller = require('egg').Controller;
const jwt = require('jsonwebtoken');
const ObjectId = require('mongodb').ObjectId;
const moment = require('moment');
class ArticlesController extends Controller {
  async getRecommend() {
    const { ctx } = this;
    const { model } = ctx;
    const result = await model.Articles.aggregate([
      {
        $match: {
          recommend: { $gte: 0 },
        },
      },
      {
        $lookup: {
          from: 'user',
          localField: 'author',
          foreignField: '_id',
          as: 'userInfo',
        },
      },
      {
        $unwind: {
          path: '$userInfo',
        },
      },
      {
        $project: {
          userInfo: { password: 0, phone: 0, mail: 0 }, // 过滤掉password
        },
      },
    ]);
    ctx.body = {
      code: 0,
      data: result,
    };
  }

  async getAllArticles() {
    const { ctx } = this;
    const { model } = ctx;
    const result = await model.Articles.aggregate([
      {
        $lookup: {
          from: 'user',
          localField: 'author',
          foreignField: '_id',
          as: 'userInfo',
        },
      },
      {
        $unwind: {
          path: '$userInfo',
        },
      },
      {
        $project: {
          userInfo: { password: 0 }, // 过滤掉password
        },
      },
    ]);
    ctx.body = {
      code: 0,
      data: result,
    };
  }

  async getArticleById() {
    const { ctx } = this;
    try {
      const { model } = ctx;
      const { id } = ctx.request.query;
      const result = await model.Articles.findOne({
        _id: ObjectId(id),
      });
      if (result) {
        ctx.body = {
          code: 0,
          data: result,
        };
      } else {
        ctx.body = {
          code: -1,
          message: 'Can not found article',
        };
      }
    } catch (e) {
      console.error(e);
      ctx.body = {
        code: -1,
        message: 'has error',
      };
    }
  }

  async getPublishedArticleById() {
    const { ctx } = this;
    try {
      const { model } = ctx;
      const { id } = ctx.request.query;
      const queryResult = await model.Articles.aggregate([
        { $match: { _id: { $eq: ObjectId(id) }, status: { $eq: 2 } } },
        { $unwind: { path: '$comment', preserveNullAndEmptyArrays: true } },
        {
          $lookup: {
            from: 'user',
            localField: 'comment.owner',
            foreignField: '_id',
            as: 'userInfo',
          },
        },
        { $unwind: { path: '$userInfo', preserveNullAndEmptyArrays: true } },
        {
          $group: {
            _id: '$_id',
            post: { $first: '$post' },
            liked: { $first: '$liked' },
            favorited: { $first: '$favorited' },
            comment: {
              $push: {
                key: '$comment.key',
                createTime: '$comment.createTime',
                content: '$comment.content',
                userId: '$comment.userId',
                name: '$userInfo.name',
                avatar: '$userInfo.avatar',
              },
            },
          },
        },
      ]);

      const result = queryResult[0];
      if (result) {
        result.comment = result.comment.filter(item => item.key);
        ctx.body = {
          code: 0,
          data: result,
        };
      } else {
        ctx.body = {
          code: -1,
          message: 'Can not found article',
        };
      }
    } catch (e) {
      console.error(e);
      ctx.body = {
        code: -1,
        message: 'has error',
      };
    }
  }

  async getPublishedArticlesByType() {
    const { ctx } = this;
    try {
      const { model } = ctx;
      const { type } = ctx.request.query;
      const result = await model.Articles.aggregate([
        {
          $match: {
            type,
            status: {
              $eq: 2,
            },
          },
        },
        {
          $lookup: {
            from: 'user',
            localField: 'author',
            foreignField: '_id',
            as: 'userInfo',
          },
        },
        {
          $unwind: {
            path: '$userInfo',
          },
        },
        {
          $project: {
            userInfo: { password: 0, phone: 0, mail: 0 }, // 过滤掉password
          },
        },
      ]);
      if (result) {
        ctx.body = {
          code: 0,
          data: result,
        };
      } else {
        ctx.body = {
          code: -1,
          message: 'Can not found article',
        };
      }
    } catch (e) {
      console.error(e);
      ctx.body = {
        code: -1,
        message: 'has error',
      };
    }
  }

  async deleteArticle() {
    const { ctx } = this;
    try {
      const { model } = ctx;
      const { id } = ctx.request.query;
      const result = await model.Articles.update(
        { _id: id },
        {
          $set: {
            status: -1,
          },
        }
      );
      if (result) {
        ctx.body = {
          code: 0,
          data: result,
        };
      } else {
        ctx.body = {
          code: -1,
          message: 'Can not found article',
        };
      }
    } catch (e) {
      console.error(e);
      ctx.body = {
        code: -1,
        message: 'service error',
      };
    }
  }

  async publish() {
    const { ctx } = this;
    try {
      const { model } = ctx;
      const { id, type } = ctx.request.query;
      const result = await model.Articles.update(
        { _id: id },
        {
          $set: {
            status: 1,
            type,
          },
        }
      );
      if (result.ok === 1) {
        ctx.body = {
          code: 0,
          data: result,
        };
      } else {
        ctx.body = {
          code: -1,
          message: '发布失败',
        };
      }
    } catch (e) {
      console.error(e);
      ctx.body = {
        code: -1,
        message: 'has error',
      };
    }
  }

  async updateArticleById() {
    const { ctx } = this;
    const { model } = ctx;
    const data = ctx.request.body;
    const id = data.id;
    const newData = {
      title: data.title,
      banner: data.banner,
      type: data.type,
      status: data.status,
      recommend: data.recommend,
      lastModify: data.lastModify,
      time: data.time,
      post: data.post,
    };
    Object.keys(newData).forEach(key => {
      if (newData[key] === undefined) {
        Reflect.deleteProperty(newData, key);
      }
    });
    const result = await model.Articles.update(
      { _id: id },
      {
        $set: newData,
      }
    );
    ctx.body = {
      code: 0,
      data: result,
    };
  }

  async initialEditor() {
    const { ctx } = this;
    const { model } = ctx;
    if (ctx.headers.token) {
      const time = moment().format('YYYY-MM-DD  HH:mm');
      const { userInfo } = jwt.decode(ctx.headers.token);
      const article = await model.Articles.insertMany([
        {
          title: '',
          type: '',
          time,
          lastModify: time,
          recommend: 0,
          status: 0,
          banner: '',
          author: ObjectId(userInfo._id),
          post: '',
          comment: [],
        },
      ]);

      ctx.body = {
        code: 0,
        data: article,
      };
    } else {
      ctx.body = {
        code: -1,
        message: '身份校验失败',
      };
    }
  }

  async getDraft() {
    const { ctx } = this;
    const { model } = ctx;
    const auth = this.authentication(ctx);
    if (auth) {
      const { userInfo } = auth;
      const draft = await model.Articles.find({
        status: { $eq: 0 },
        author: userInfo._id,
      });
      ctx.body = {
        code: 0,
        data: draft,
      };
    } else {
      ctx.body = {
        code: -1,
        message: '身份校验失败',
      };
    }
  }

  async getFavorited() {
    const { ctx } = this;
    const { model } = ctx;
    const auth = this.authentication(ctx);
    if (auth) {
      const { userInfo } = auth;
      const result = await model.User.aggregate([
        {
          $match: {
            _id: ObjectId(userInfo._id),
          },
        },
        {
          $project: {
            favorited: 1,
          },
        },
        {
          $unwind: '$favorited',
        },
        {
          $lookup: {
            from: 'articles',
            localField: 'favorited',
            foreignField: '_id',
            as: 'articleInfo',
          },
        },
        {
          $unwind: '$articleInfo',
        },
        {
          $group: {
            _id: '$_id',
            articles: {
              $push: {
                title: '$articleInfo.title',
                _id: '$articleInfo._id',
                post: '$articleInfo.post',
              },
            },
          },
        },
      ]);
      if (Array.isArray(result) && result.length > 0) {
        ctx.body = {
          code: 0,
          data: result[0].articles,
        };
      } else {
        ctx.body = {
          code: 0,
          data: [],
        };
      }
    } else {
      ctx.body = {
        code: -1,
        message: '身份校验失败',
      };
    }
  }

  async getReview() {
    const { ctx } = this;
    const { model } = ctx;
    const auth = this.authentication(ctx);
    if (auth) {
      const { userInfo } = auth;
      const review = await model.Articles.find({
        status: { $eq: 1 },
        author: userInfo._id,
      });
      ctx.body = {
        code: 0,
        data: review,
      };
    } else {
      ctx.body = {
        code: -1,
        message: '身份校验失败',
      };
    }
  }

  async getPosts() {
    const { ctx } = this;
    const { model } = ctx;
    const auth = this.authentication(ctx);
    if (auth) {
      const { userInfo } = auth;
      const posts = await model.Articles.find({
        status: { $eq: 2 },
        author: userInfo._id,
      });
      ctx.body = {
        code: 0,
        data: posts,
      };
    } else {
      ctx.body = {
        code: -1,
        message: '身份校验失败',
      };
    }
  }

  async commentArticle() {
    const { ctx } = this;
    try {
      const { model } = ctx;
      const auth = this.authentication(ctx);
      const now = String(Date.now());
      if (auth) {
        const { userInfo } = auth;
        const { pid, content } = ctx.request.body;
        const post = await model.Articles.findOne({
          _id: pid,
        });
        const comments = post.comment || [];
        const count =
          comments.filter(comment => /^((?!#).)*$/.test(comment.key)).length +
          1;
        const key = String(count);
        const res = await model.Articles.updateOne(
          {
            _id: pid,
          },
          {
            $push: {
              comment: {
                key,
                content,
                owner: userInfo._id,
                status: 0,
                createTime: now,
              },
            },
          }
        );
        if (res) {
          const article = await model.Articles.findOne(
            {
              _id: pid,
            }
          );
          if (article) {
            const author = article.author;
            await model.User.update(
              { _id: author },
              {
                $push: {
                  messages: {
                    messageType: 'commentArticle',
                    time: now,
                    fromUser: ObjectId(userInfo._id),
                    articleId: ObjectId(pid),
                    content,
                  },
                },
              });
          }
          ctx.body = {
            code: 0,
            data: {
              key,
              content,
              owner: userInfo._id,
              status: 0,
              createTime: now,
            },
            message: 'ok',
          };
        } else {
          ctx.body = {
            code: -1,
            message: '评论失败',
          };
        }
      } else {
        ctx.body = {
          code: -1,
          message: '身份校验失败',
        };
      }
    } catch (error) {
      ctx.body = {
        code: -1,
        message: 'service error',
      };
    }
  }

  async commentReply() {
    const { ctx } = this;
    try {
      const { model } = ctx;
      const auth = this.authentication(ctx);
      if (auth) {
        const { userInfo } = auth;
        const { pid, content, parentKey } = ctx.request.body;
        const post = await model.Articles.findOne({
          _id: pid,
        });
        const comments = post.comment || [];
        const reg = new RegExp(`^${parentKey}#\\d+$`);
        const count =
          comments.filter(comment => reg.test(comment.key)).length +
          1;
        const key = `${parentKey}#${count}`;
        const createTime = moment().format('YYYY-MM-DD HH:mm');
        const res = await model.Articles.updateOne(
          {
            _id: pid,
          },
          {
            $push: {
              comment: {
                key,
                content,
                owner: userInfo._id,
                status: 0,
                createTime,
              },
            },
          }
        );
        if (res) {
          ctx.body = {
            code: 0,
            data: {
              key,
              content,
              owner: userInfo._id,
              status: 0,
              createTime,
            },
            message: 'ok',
          };
        } else {
          ctx.body = {
            code: -1,
            message: '评论失败',
          };
        }
      } else {
        ctx.body = {
          code: -1,
          message: '身份校验失败',
        };
      }
    } catch (error) {
      ctx.body = {
        code: -1,
        message: 'service error',
      };
    }
  }

  async likeArticleById() {
    const { ctx } = this;
    try {
      const { model } = ctx;
      const { id, userId } = ctx.request.body;
      const auth = this.authentication(ctx);
      const now = String(Date.now());
      if (auth) {
        console.log(auth);
        const queryResult = await model.Articles.findOne({ _id: id });
        const liked = queryResult.liked || [];
        const author = queryResult.author;
        if (liked.indexOf(userId) > -1) {
          await model.Articles.update({ _id: id }, { $pull: { liked: userId } });
          await model.User.update({ _id: author }, { $pull: { liked_me: userId } });
          ctx.body = {
            code: 0,
            data: {
              type: -1,
            },
          };
        } else {
          await model.Articles.update({ _id: id }, { $push: { liked: userId } });
          await model.User.update(
            { _id: author },
            {
              $push: {
                liked_me: userId,
                messages: {
                  messageType: 'liked',
                  time: now,
                  fromUser: ObjectId(userId),
                  articleId: ObjectId(id),
                },
              },
            });
          ctx.body = {
            code: 0,
            data: {
              type: 1,
            },
          };
        }
      } else {
        ctx.body = {
          code: -1,
          message: '身份校验失败',
        };
      }
    } catch (e) {
      console.error(e);
      ctx.body = {
        code: -1,
        message: 'service error',
      };
    }
  }

  async favoritedArticleById() {
    const { ctx } = this;
    try {
      const { model } = ctx;
      const { id, userId } = ctx.request.body;
      const auth = this.authentication(ctx);
      if (auth) {
        const queryResult = await model.Articles.findOne({ _id: id });
        const favorited = queryResult.favorited || [];
        if (favorited.indexOf(userId) > -1) {
          await model.Articles.update({ _id: id }, { $pull: { favorited: userId } });
          await model.User.update({ _id: userId }, { $pull: { favorited: id } });
          ctx.body = {
            code: 0,
            data: {
              type: -1,
            },
          };
        } else {
          await model.Articles.update({ _id: id }, { $push: { favorited: userId } });
          await model.User.update({ _id: userId }, { $push: { favorited: id } });
          ctx.body = {
            code: 0,
            data: {
              type: 1,
            },
          };
        }
      } else {
        ctx.body = {
          code: -1,
          message: '身份校验失败',
        };
      }
    } catch (e) {
      console.error(e);
      ctx.body = {
        code: -1,
        message: 'service error',
      };
    }
  }

  async search() {
    const { ctx } = this;
    try {
      const { model } = ctx;
      const { text } = ctx.request.query;
      const queryResult = await model.Articles.aggregate(
        [{
          $match:
          { $text:
            { $search: text },
          },
        },
        {
          $lookup: {
            from: 'user',
            localField: 'author',
            foreignField: '_id',
            as: 'userInfo',
          },
        },
        {
          $unwind: {
            path: '$userInfo',
          },
        },
        {
          $project: {
            userInfo: { password: 0, phone: 0, mail: 0 }, // 过滤掉password
          },
        }]
      );
      ctx.body = {
        code: 0,
        data: queryResult,
      };
    } catch (e) {
      console.error(e);
      ctx.body = {
        code: -1,
        message: 'service error',
      };
    }
  }

  authentication(ctx) {
    if (ctx.headers.token) {
      return jwt.decode(ctx.headers.token);
    }
    ctx.body = {
      code: -1,
      message: '身份校验失败，请重新登陆',
    };
    return false;
  }
}

module.exports = ArticlesController;
